home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Toolbox / Visual Basic Toolbox (P.I.E.)(1996).ISO / graphics / 256pb2 / dib.c < prev    next >
C/C++ Source or Header  |  1992-03-12  |  14KB  |  428 lines

  1. //-----------------------------------------------------------------------------
  2. // DIB.C
  3. //
  4. // This is a collection of useful DIB manipulation/information gathering
  5. // functions.  Many functions are supplied simply to take the burden
  6. // of taking into account whether a DIB is a Win30 style or OS/2 style
  7. // DIB away from the application.
  8. //
  9. // The functions in this module assume that the DIB pointers or handles
  10. // passed to them point to a block of memory in one of two formats:
  11. //
  12. //       a) BITMAPINFOHEADER + color table + DIB bits (3.0 style DIB)
  13. //       b) BITMAPCOREHEADER + color table + DIB bits (OS/2 PM style)
  14. //
  15. // The SDK Reference, Volume 2 describes these data structures.
  16. //
  17. // A number of functions in this module were lifted from SHOWDIB,
  18. // and modified to handle OS/2 DIBs.
  19. //
  20. // The functions in this module could be streamlined (made faster and
  21. // smaller) by removing the OS/2 DIB specific code, and assuming all
  22. // DIBs passed to it are Win30 style DIBs.  The DIB file reading code
  23. // would need to be modified to always convert DIBs to Win30 style
  24. // DIBs.  The only reason this isn't done in DIBView is because DIBView
  25. // was written to test display and printer drivers (which are supposed
  26. // to support OS/2 DIBs wherever they support Win30 style DIBs).  SHOWDIB
  27. // is a great example of how to go about doing this.
  28. //-----------------------------------------------------------------------------
  29.  
  30. #include <windows.h>
  31. #include <memory.h>
  32. #include "errors.h"
  33. #include "dib.h"
  34.  
  35. //---------------------------------------------------------------------
  36. //
  37. // Function:   FindDIBBits
  38. //
  39. // Purpose:    Given a pointer to a DIB, returns a pointer to the
  40. //             DIB's bitmap bits.
  41. //
  42. // Parms:      lpbi == pointer to DIB header (either BITMAPINFOHEADER
  43. //                       or BITMAPCOREHEADER)
  44. //
  45. // History:   Date      Reason
  46. //             6/01/91  Created
  47. //
  48. //---------------------------------------------------------------------
  49.  
  50. LPSTR FAR PASCAL FindDIBBits (LPSTR lpbi)
  51. {
  52.    return (lpbi + *(LPDWORD)lpbi + PaletteSize (lpbi));
  53. }
  54.  
  55. //---------------------------------------------------------------------
  56. //
  57. // Function:   DIBNumColors
  58. //
  59. // Purpose:    Given a pointer to a DIB, returns a number of colors in
  60. //             the DIB's color table.
  61. //
  62. // Parms:      lpbi == pointer to DIB header (either BITMAPINFOHEADER
  63. //                       or BITMAPCOREHEADER)
  64. //
  65. // History:   Date      Reason
  66. //             6/01/91  Created
  67. //
  68. //---------------------------------------------------------------------
  69.  
  70. WORD FAR PASCAL DIBNumColors (LPSTR lpbi)
  71. {
  72.    WORD wBitCount;
  73.  
  74.  
  75.       // If this is a Windows style DIB, the number of colors in the
  76.       //  color table can be less than the number of bits per pixel
  77.       //  allows for (i.e. lpbi->biClrUsed can be set to some value).
  78.       //  If this is the case, return the appropriate value.
  79.  
  80.    if (IS_WIN30_DIB (lpbi))
  81.       {
  82.       DWORD dwClrUsed;
  83.  
  84.       dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
  85.  
  86.       if (dwClrUsed)
  87.          return (WORD) dwClrUsed;
  88.       }
  89.  
  90.  
  91.       // Calculate the number of colors in the color table based on
  92.       //  the number of bits per pixel for the DIB.
  93.  
  94.    if (IS_WIN30_DIB (lpbi))
  95.       wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
  96.    else
  97.       wBitCount = ((LPBITMAPCOREHEADER) lpbi)->bcBitCount;
  98.  
  99.    switch (wBitCount)
  100.       {
  101.       case 1:
  102.          return 2;
  103.  
  104.       case 4:
  105.          return 16;
  106.  
  107.       case 8:
  108.          return 256;
  109.  
  110.       default:
  111.          return 0;
  112.       }
  113. }
  114.  
  115. //---------------------------------------------------------------------
  116. //
  117. // Function:   PaletteSize
  118. //
  119. // Purpose:    Given a pointer to a DIB, returns number of bytes
  120. //             in the DIB's color table.
  121. //
  122. // Parms:      lpbi == pointer to DIB header (either BITMAPINFOHEADER
  123. //                       or BITMAPCOREHEADER)
  124. //
  125. // History:   Date      Reason
  126. //             6/01/91  Created
  127. //
  128. //---------------------------------------------------------------------
  129.  
  130. WORD FAR PASCAL PaletteSize (LPSTR lpbi)
  131. {
  132.    if (IS_WIN30_DIB (lpbi))
  133.       return (DIBNumColors (lpbi) * sizeof (RGBQUAD));
  134.    else
  135.       return (DIBNumColors (lpbi) * sizeof (RGBTRIPLE));
  136. }
  137.  
  138. //---------------------------------------------------------------------
  139. //
  140. // Function:   CreateDIBPalette
  141. //
  142. // Purpose:    Given a handle to a DIB, constructs a logical palette,
  143. //             and returns a handle to this palette.
  144. //
  145. //             Stolen almost verbatim from ShowDIB.
  146. //
  147. // Parms:      hDIB == HANDLE to global memory with a DIB header
  148. //                     (either BITMAPINFOHEADER or BITMAPCOREHEADER)
  149. //
  150. // History:   Date      Reason
  151. //             6/01/91  Created
  152. //
  153. //---------------------------------------------------------------------
  154.  
  155. HPALETTE FAR PASCAL CreateDIBPalette (HANDLE hDIB)
  156. {
  157.    LPLOGPALETTE     lpPal;
  158.    HANDLE           hLogPal;
  159.    HPALETTE         hPal = NULL;
  160.    int              i, wNumColors;
  161.    LPSTR            lpbi;
  162.    LPBITMAPINFO     lpbmi;
  163.    LPBITMAPCOREINFO lpbmc;
  164.    BOOL             bWinStyleDIB;
  165.  
  166.    if (!hDIB)
  167.       return NULL;
  168.  
  169.    lpbi         = GlobalLock (hDIB);
  170.    lpbmi        = (LPBITMAPINFO) lpbi;
  171.    lpbmc        = (LPBITMAPCOREINFO) lpbi;
  172.    wNumColors   = DIBNumColors (lpbi);
  173.    bWinStyleDIB = IS_WIN30_DIB (lpbi);
  174.  
  175.    if (wNumColors)
  176.       {
  177.       hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) +
  178.                              sizeof (PALETTEENTRY) * wNumColors);
  179.  
  180.       if (!hLogPal)
  181.          {
  182.          DIBError (ERR_CREATEPAL);
  183.          GlobalUnlock (hDIB);
  184.          return NULL;
  185.          }
  186.  
  187.       lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
  188.  
  189.       lpPal->palVersion    = PALVERSION;
  190.       lpPal->palNumEntries = wNumColors;
  191.  
  192.       for (i = 0;  i < wNumColors;  i++)
  193.          {
  194.          if (bWinStyleDIB)
  195.             {
  196.             lpPal->palPalEntry[i].peRed   = lpbmi->bmiColors[i].rgbRed;
  197.             lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  198.             lpPal->palPalEntry[i].peBlue  = lpbmi->bmiColors[i].rgbBlue;
  199.             lpPal->palPalEntry[i].peFlags = 0;
  200.             }
  201.          else
  202.             {
  203.             lpPal->palPalEntry[i].peRed   = lpbmc->bmciColors[i].rgbtRed;
  204.             lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  205.             lpPal->palPalEntry[i].peBlue  = lpbmc->bmciColors[i].rgbtBlue;
  206.             lpPal->palPalEntry[i].peFlags = 0;
  207.             }
  208.          }
  209.  
  210.       hPal = CreatePalette (lpPal);
  211.  
  212.       if (!hPal)
  213.          DIBError (ERR_CREATEPAL);
  214.  
  215.       GlobalUnlock (hLogPal);
  216.       GlobalFree   (hLogPal);
  217.    }
  218.  
  219.    GlobalUnlock (hDIB);
  220.  
  221.    return hPal;
  222. }
  223.  
  224. //---------------------------------------------------------------------
  225. //
  226. // Function:   DIBHeight
  227. //
  228. // Purpose:    Given a pointer to a DIB, returns its height.  Note
  229. //             that it returns a DWORD (since a Win30 DIB can have
  230. //             a DWORD in its height field), but under Win30, the
  231. //             high order word isn't used!
  232. //
  233. // Parms:      lpDIB == pointer to DIB header (either BITMAPINFOHEADER
  234. //                       or BITMAPCOREHEADER)
  235. //
  236. // History:   Date      Reason
  237. //             6/01/91  Created
  238. //
  239. //---------------------------------------------------------------------
  240.  
  241. DWORD FAR PASCAL DIBHeight (LPSTR lpDIB)
  242. {
  243.    LPBITMAPINFOHEADER lpbmi;
  244.    LPBITMAPCOREHEADER lpbmc;
  245.  
  246.    lpbmi = (LPBITMAPINFOHEADER) lpDIB;
  247.    lpbmc = (LPBITMAPCOREHEADER) lpDIB;
  248.  
  249.    if (lpbmi->biSize == sizeof (BITMAPINFOHEADER))
  250.       return lpbmi->biHeight;
  251.    else
  252.       return (DWORD) lpbmc->bcHeight;
  253. }
  254.  
  255. //---------------------------------------------------------------------
  256. //
  257. // Function:   DIBWidth
  258. //
  259. // Purpose:    Given a pointer to a DIB, returns its width.  Note
  260. //             that it returns a DWORD (since a Win30 DIB can have
  261. //             a DWORD in its width field), but under Win30, the
  262. //             high order word isn't used!
  263. //
  264. // Parms:      lpDIB == pointer to DIB header (either BITMAPINFOHEADER
  265. //                       or BITMAPCOREHEADER)
  266. //
  267. // History:   Date      Reason
  268. //             6/01/91  Created
  269. //
  270. //---------------------------------------------------------------------
  271.  
  272. DWORD FAR PASCAL DIBWidth (LPSTR lpDIB)
  273. {
  274.    LPBITMAPINFOHEADER lpbmi;
  275.    LPBITMAPCOREHEADER lpbmc;
  276.  
  277.    lpbmi = (LPBITMAPINFOHEADER) lpDIB;
  278.    lpbmc = (LPBITMAPCOREHEADER) lpDIB;
  279.  
  280.    if (lpbmi->biSize == sizeof (BITMAPINFOHEADER))
  281.       return lpbmi->biWidth;
  282.    else
  283.       return (DWORD) lpbmc->bcWidth;
  284. }
  285.  
  286. //---------------------------------------------------------------------
  287. //
  288. // Function:   DIBLoad
  289. //
  290. // Purpose:    Given a pointer to a DIB filename, will open that file
  291. //             and read the DIB data into a globally allocated memory
  292. //             block.
  293. //
  294. // Parms:      lpszDIBName == pointer to a string containing the name
  295. //                (any valid DOS filename) of the DIB file
  296. //
  297. // Returns:    Will return a handle to the global memory block if
  298. //               successful.  Will return NULL otherwise.
  299. //
  300. // History:    Date     Reason
  301. //             3/10/92  Created
  302. //
  303. //---------------------------------------------------------------------
  304.  
  305. HANDLE FAR PASCAL DIBLoad (LPSTR lpszDIBName)
  306. {
  307.     unsigned           fh;
  308.     LPBITMAPINFOHEADER lpbi;
  309.     OFSTRUCT           of;
  310.     BITMAPFILEHEADER   bf;
  311.     WORD               nNumColors;
  312.     WORD               offBits;
  313.     HANDLE               hDIBInfo = NULL;
  314.     char *               szMsg;
  315.     HANDLE             result = NULL;         /* assume failure */
  316.  
  317.     /* Open the file and get a handle to it's BITMAPINFO */
  318.  
  319.     hDIBInfo = GlobalAlloc(GMEM_MOVEABLE,
  320.                    (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
  321.     if (hDIBInfo == NULL) {
  322.         wsprintf((LPSTR) szMsg, "Not enough memory to load '%s'", lpszDIBName);
  323.         MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
  324.         return (NULL);
  325.     }
  326.  
  327.     lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIBInfo);
  328.  
  329.     fh = OpenFile (lpszDIBName, &of, OF_READ);
  330.     if (fh == -1) {
  331.         wsprintf((LPSTR) szMsg, "Can't open file '%s'", lpszDIBName);
  332.         MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
  333.         return (NULL);
  334.     }
  335.  
  336.     /* read the BITMAPFILEHEADER */
  337.     if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
  338.         goto ErrExit;
  339.  
  340.     if (bf.bfType != 0x4d42)    /* 'BM' */
  341.         goto ErrExit;
  342.  
  343.     if (sizeof(BITMAPINFOHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
  344.         goto ErrExit;
  345.  
  346.     /* don't even deal with OS/2 bitmaps */
  347.     if (!IS_WIN30_DIB(lpbi)) {
  348.         wsprintf((LPSTR) szMsg, "OS/2 bitmaps (%s) not supported!", lpszDIBName);
  349.         MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
  350.         goto ErrExit;
  351.     }
  352.  
  353.     if (!(nNumColors = (WORD)lpbi->biClrUsed))
  354.     {
  355.         /* no color table for 24-bit, default size otherwise */
  356.         if (lpbi->biBitCount != 24)
  357.             nNumColors = 1 << lpbi->biBitCount; /* standard size table */
  358.     }
  359.  
  360.     /*  fill in some default values if they are zero */
  361.     if (lpbi->biClrUsed == 0)
  362.         lpbi->biClrUsed = (DWORD)nNumColors;
  363.  
  364.     if (lpbi->biSizeImage == 0)
  365.     {
  366.         lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
  367.                          * lpbi->biHeight;
  368.     }
  369.  
  370.     /* get a proper-sized buffer for header, color table and bits */
  371.     GlobalUnlock(hDIBInfo);
  372.     hDIBInfo = GlobalReAlloc(hDIBInfo, lpbi->biSize +
  373.                                         nNumColors * sizeof(RGBQUAD) +
  374.                                         lpbi->biSizeImage, 0);
  375.     if (!hDIBInfo) {     /* can't resize buffer for loading */
  376.         wsprintf((LPSTR) szMsg, "Not enough memory to load '%s'", lpszDIBName);
  377.         MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
  378.         goto ErrExit;
  379.     }
  380.  
  381.     lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIBInfo);
  382.  
  383.     /* read the color table */
  384.     _lread (fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
  385.  
  386.     /* offset to the bits from start of DIB header */
  387.     offBits = (WORD)lpbi->biSize + nNumColors * sizeof(RGBQUAD);
  388.  
  389.     if (bf.bfOffBits != 0L)
  390.     {
  391.         _llseek(fh,bf.bfOffBits, SEEK_SET);
  392.     }
  393.     if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
  394.         result = hDIBInfo;
  395.  
  396. ErrExit:
  397.     _lclose(fh);
  398.     GlobalUnlock(hDIBInfo);
  399.     return(result);
  400. }
  401.  
  402. /**************** PRIVATE ROUTINE TO READ MORE THAN 64K *********************/
  403. /****************************************************************************
  404.  *                                                                          *
  405.  *  FUNCTION   : lread(int fh, VOID FAR *pv, DWORD ul)                      *
  406.  *                                                                          *
  407.  *  PURPOSE    : Reads data in steps of 32k till all the data has been read.*
  408.  *                                                                          *
  409.  *  RETURNS    : 0 - If read did not proceed correctly.                     *
  410.  *               number of bytes read otherwise.                            *
  411.  *                                                                          *
  412.  ****************************************************************************/
  413. DWORD PASCAL lread (int fh, VOID far *pv, DWORD ul)
  414. {
  415.     DWORD     ulT = ul;
  416.     BYTE huge *hp = pv;
  417.  
  418.     while (ul > (DWORD)MAXREAD) {
  419.         if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
  420.                 return 0;
  421.         ul -= MAXREAD;
  422.         hp += MAXREAD;
  423.     }
  424.     if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
  425.         return 0;
  426.     return ulT;
  427. }
  428.